﻿
using System.Buffers;
using Geek.Server.Core.Hotfix;
using Geek.Server.Core.Serialize;




namespace Geek.Server.Core.Net.Tcp
{
    public class MsgPackDispatcher : BaseDispatcher
    {

        // 解析消息
        // 消息
        protected long lastReviceTime = 0;
        protected int lastOrder = 0;

        protected override int MinRecvSize => 16;

        public override bool TryParse(ref ReadOnlySequence<byte> input, out object msg)
        {
            msg = default;
            var bufEnd = input.End;
            var reader = new SequenceReader<byte>(input);

            //获得消息长度
            if (!reader.TryReadBigEndian(out int msgLen))
            {
                return false;
            }

            //检查长度是否合法
            if (!CheckMsgLen(msgLen))
            {
                throw new Exception("消息长度异常");
            }
            //看看读了多少了
            if (reader.Remaining < msgLen - 4)
            {
                return false;
            }
            // 获得需要解析的内容
            var payload = input.Slice(reader.Position, msgLen - 4);

            //读取第一个数据段，时间
            reader.TryReadBigEndian(out long time);
            if (!CheckTime(time))
            {
                throw new Exception("消息接收时间错乱");
            }
            // 第二字段order
            reader.TryReadBigEndian(out int order);
            if (!CheckMagicNumber(order, msgLen))
            {
                throw new Exception("消息order错乱");
            }
            // 第三个字段 消息类型
            reader.TryReadBigEndian(out int msgId);

            var msgType = HotfixMgr.GetMsgType(msgId);
            if (msgType == null)
            {
                LOGGER.Error("消息ID:{} 找不到对应的Msg.", msgId);
            }
            else
            {
                // 解析真正的数据
                var message = Serializer.Deserialize<Message>(payload.Slice(16));
                if (message.MsgId != msgId)
                {
                    throw new Exception($"解析消息错误，注册消息id和消息无法对应.real:{message.MsgId}, register:{msgId}");
                }
                msg = message;
            }
            input = input.Slice(input.GetPosition(msgLen));
            return true;
        }

        /// <summary>
        /// 分发数据
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override async Task Dispatcher(Object obj)
        {

            var msg = obj as Message;
            if (msg == null)
                return;

            // LOGGER.Debug($"-------------收到消息{msg.MsgId} {msg.GetType()}");
            // 根据消息类型解析出对应的handler句柄
            var handler = HotfixMgr.GetTcpHandler(msg.MsgId);
            if (handler == null)
            {
                LOGGER.Error($"找不到[{msg.MsgId}][{msg.GetType()}]对应的handler");
                return;
            }
            // 绑定一个handle,让handle对内容进行绑定，然后执行动作
            handler.Msg = msg;
            handler.Channel = Channel;
            await handler.Init();
            await handler.InnerAction();
        }

        /// <summary>
        /// 转换为byte数据
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override Span<byte> ParseToByte(object obj)
        {
            var msg=obj as Message;
            var bytes = Serializer.Serialize(msg);
            int len = 8 + bytes.Length;
            Span<byte> span = new byte[len];
            int offset = 0;
            // 写入协议长度
            span.WriteInt(len, ref offset);
            // 写入协议ID
            span.WriteInt(msg.MsgId, ref offset);
            // 吸入数据
            span.WriteBytesWithoutLength(bytes, ref offset);
            return span;
        }

        /// <summary>
        /// 时间戳检查(可以防止客户端游戏过程中修改时间)
        /// </summary>
        /// <param name="context"></param>
        /// <param name="time"></param>
        /// <returns></returns>
        protected bool CheckTime(long time)
        {
            if (lastReviceTime > time)
            {
                LOGGER.Error("时间戳出错，time=" + time + ", lastTime=" + lastReviceTime);
                return false;
            }
            lastReviceTime = time;
            return true;
        }

        /// <summary>
        /// 消息加密
        /// </summary>
        /// <param name="order"></param>
        /// <param name="msgLen"></param>
        /// <returns></returns>
        protected bool CheckMagicNumber(int order, int msgLen)
        {
            order ^= 0x1234 << 8;
            order ^= msgLen;

            if (lastOrder != 0 && order != lastOrder + 1)
            {
                LOGGER.Error("包序列出错, order=" + order + ", lastOrder=" + lastOrder);
                return false;
            }
            lastOrder = order;
            return true;
        }
       
    }
}
